import javax.swing.JFrame;


public class RendererFlat extends JFrame{

	float Alpha = 0.0f, Beta = 0.0f; // initial turning angles
	float Angle_step = 0.25f;  // increment of turning angle
	float Min_angle = -1.5f;
	float Max_angle = 1.5f;
	float Sina, Cosa, Sinb, Cosb; // sin & cos of Alpha and Beta
	float Tana, Casb, Cacb; // tan(Alpha), Cosa*Sinb, Cosa*Cosb
	float Sasb, Sacb;  // Sina*Sinb, Sina*Cosb
	float Ratio; // ratio of screen size over max coordinate values
	boolean Shade; // shade or regular
	boolean Norm; // interpolation flag: TRUE - normal, FALSE - intensity
	boolean Ridge; // special ridge treatment
	int Maxx, Maxy;  // maximum coordinates of x and y
	int Midx, Midy;  // coordinates of screen middle
	float Ip;  // intensity of point light
	float Dist;
	float T_step3 = 0.1f; //T_STEP*T_STEP*T_STEP;
	//Intrpl Intr, Intrpl_x, Intrpl_z, Intrpl_Z ; // structures for interpolation
	
	boolean Write_flag;  // flag indicating if output goes to image file
	//char Buf[1440]; // buffer for rgb values for file
	int screen[][] = new int[640][480]; // virtual screen
	//Fhr fhr[1024];
	float D1 ;  // dist of viewpoint from screen
	float D2 ;  // dist of screen from origin
	float D22;  // Original distance of screen from origin
	float D3 ;  // dist of viewpoint from origin (D1+D2)
	float Thldn; // Threshold value for LdotN - see Intensity()
	float Thin;  // Threshold for intensity
	float NEG_ST, POS_ST;  // limiting values for t-plane
	float RADIUS = 1.0f;
	float AMBIENT = 0.5f;
	float FUNC(float a, float b) { return 1.0f; }
	
	public class FHR {
		public int ymin;
		public int ymax; 
		public int yprev;
		
		public FHR() { ymin = 0; }
	}
	
	public void Putpixel(int x, int y, int base, float intens){
		screen[x][y] = base;
	}
	
	void flh_regular()
	// Regular floating horizon - no shading
	//======================================
	{ 
		FHR fhr[] = new FHR[1024];
		for (int i = 0; i < 1024; ++i)
			fhr[i] = new FHR();
	 // clock_t btime;  /* this type is defined in time.h */
	  //double cps = (double)CLOCKS_PER_SEC;
	  float z, X, Y;  // , xtag, ytag, ztag;
	  float zsa, zca, zsb, zcb;
	  int XS, YS, firstXS, lastXS;
	  int j, jstep;
	  //btime = clock();
	  //memset(screen, 0, (Maxx+1)*(Maxy+1));
	  //TODO: init array
	  //TODO: what is radius?
	  float RADIUS = 10.0f;
	  firstXS = Midx + (int)(-RADIUS*Ratio);
	  lastXS  = Midx + (int)(RADIUS*Ratio);
	  float r1, u, v, w, y1, z1;
	  float xtag,ytag,ztag;
	  //printf("\nD1 = %g\n", D1);
	  for (XS = firstXS; XS <= lastXS; XS++)
	     { 
		  
		   fhr[XS].ymin = Integer.MAX_VALUE;  // Initialize min value in column.  
	       fhr[XS].ymax = Integer.MIN_VALUE; // Initialize max value in column.
	     }
	  //TODO: T_STEP and FUN_MAX 
	  float T_STEP = 0.3f;
	  float FUN_MAX = 1.0f;
	  
	  for (z = NEG_ST; z <= POS_ST; z += T_STEP)
	     { zsb = z*Sinb; zcb = z*Cosb; 
	       zsa = z*Sina; zca = z*Cosa;
	       if (FUN_MAX*Sina + zca <= -D2) continue;
	       for (XS = firstXS; XS <= lastXS; XS++) {
	          X = (XS - Midx)/Ratio;
	          xtag = X*Cosb + zsb;
	          ztag = -X*Sinb + zcb;
	          ytag = FUNC(xtag, ztag); // calculate function
	          Y = ytag*Cosa - zsa;
	            r1 = X*(zca + D3)/D1;
	            u = r1*Cosb + zsb;
	            v = -r1*Sinb + zcb;
	            w = FUNC(u,v);
	            y1 = w*Cosa - zsa;
	            z1 = w*Sina + zca;
	            Y = y1*D1/(z1+D3);
	            YS = (int)Math.round(Y*Ratio + Midy); //TODO: check validity
	            if (YS < 0) YS = -1;          // don't waste time on
	            if (YS > Maxy) YS = Maxy + 1; // invisible pixels
	            if (fhr[XS].ymin==Integer.MAX_VALUE && fhr[XS].ymax==Integer.MIN_VALUE)
	               { // First pixel in column:
	                 fhr[XS].ymin = fhr[XS].ymax = fhr[XS].yprev = YS;
	                 if (XS == firstXS) // check if first column 
	                    Putpixel(XS, YS, 0, 0.0f);
	                 else  // draw line segment for continuity
	                    Line (XS-1, fhr[XS-1].yprev, XS, YS);
	               }
	            else // not first pixel in column - check if visible:
	               { if (YS < fhr[XS].ymin) // below minimum for column
	                    { fhr[XS].ymin = fhr[XS].yprev = YS;
	                      if (XS == firstXS) // check if first column 
	                         Putpixel(XS, YS, 0, 0.0f);
	                      else  // draw line segment for continuity
	                         Line (XS-1, fhr[XS-1].ymin, XS, YS);
	                    }
	                 else if (YS > fhr[XS].ymax) // above maximum for column
	                    { fhr[XS].ymax = fhr[XS].yprev = YS;
	                      if (XS == firstXS) // check if first column 
	                         Putpixel(XS, YS, 0, 0.0f);
	                      else  // draw line segment for continuity
	                         Line (XS-1, fhr[XS-1].ymax, XS, YS);
	                    }
	                 else if (XS > firstXS) // check if partial line needed:
	                    { if (fhr[XS-1].yprev > fhr[XS].ymax)
	                         Line (XS-1, fhr[XS-1].yprev, XS, fhr[XS].ymax);
	                      else if (fhr[XS-1].yprev < fhr[XS].ymin)
	                         Line (XS-1, fhr[XS-1].yprev, XS, fhr[XS].ymin);
	                    }
	               }
	          } // of x axis for
	     } // of z axis for
	// write image to file:
	//       if (Write_flag)
	  //        for (XS = firstXS; XS <= lastXS; XS++)
	    //         { for (j=0; j<=Maxy; j++)
	      //            { int val = (screen[XS][j]!=0) ? 0 : 255 ;
	        //            fputc(val, Imgfile);
//	                  if (fputc(val, Imgfile) == EOF)
//	                  Errexit("Error writing to Imgfile in flh_regular.");
//	                  }
	//             }
//	  printf("\nElapsed time: %lg sec.\n", (clock()-btime)/cps);
	} // end of flh_regular


	//==============================================
	float Intensity(float ldotn, float z)
	// Return intensity based on normal and distance
	//==============================================
	{ float intens;
	  float denom = z/RADIUS + Dist;
	  if (ldotn < Thldn) ldotn = Thldn;
	  if (denom < 1.e-7) intens = 1.0f;
	  else
	     { intens = AMBIENT + Ip*ldotn/denom;
	       if (intens > 1.0) intens = 1.0f;
	     }
	  return (intens);
	} // end of Intensity


	//=======================================
	 void Line(int x1, int y1, int x2, int y2)
	//=======================================
	{ int i, y3 = (y1 + y2) / 2 ;
	  if (y1 < y2)
	     { for (i=y1+1; i<=y3; i++) Putpixel(x1, i, 0, 0.0f);
	       for (i=y3+1; i<=y2; i++) Putpixel(x2, i, 0, 0.0f);
	     }
	  else if (y1 > y2)
	     { for (i=y1-1; i>y3; i--) Putpixel(x1, i, 0, 0.0f);
	       for (i=y3; i>=y2; i--) Putpixel(x2, i, 0, 0.0f);
	     }
	  else Putpixel(x2, y2, 0, 0.0f);
	} // end of Line.

	//=================================================
	 
	//=================================================
//	{ int r, g, b;
//	  // putpixel(x, y, base + (int)(intens*NUM_COLORS));
//	  if (y<0 || y>Maxy) return;  // pixel not in viewport
//	  if (!Shade)  // BW display:  
//	     screen[x][y] = 1;
//	  else // shaded display:
//	     { // write RGB values to output buffer
//	       g = b = (int)(intens*255);
//	       r = (base==64) ? g : 0 ;
//	     //  Buf[y*3] = r;
//	     //  Buf[y*3+1] = g;
//	     //  Buf[y*3+2] = b;
//	     }
//	}

	 public static void main(String[] args) { 
		RendererFlat rf =  new RendererFlat();
		rf.flh_regular();
		rf.add(new ImagePanel(  rf.screen[0], 63, 9));
		
		rf.pack();
		rf.setVisible(true);
	 
	 }
}
